/*
 * conexiones.c
 *
 *  Created on: 22/10/2011
 *      Author: utn_so
 */
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
#include "Fuselage_Sockets.h"
#include "constantes.h"
#include "conexiones.h"
#include "iniciarFat.h"
#include <semaphore.h>
#include <pthread.h>
#include "funciones_NIPC.h"
#include "estaticas.h"
#include <semaphore.h>
#include <errno.h>

sem_t conexionesTotales;

/* DAN: int32_t generarColaConexiones(int32_t cantidadConexiones)*/
struct poolConexiones *generarColaConexiones() {

	log_info(log, "CONEXIONES", "Inicio generarColaConexiones");

//DAN:	uint32_t exit= 0;

//Genero la cantidad de conexiones que me vienen por parámetro y las meto en un array de conexiones.
	uint32_t i = 0;

	if (sem_init(&conexionesTotales, 0, config.iCantMaxConex)) {
		log_error(log, "CONEXIONES",
				"No se pudo crear el semáforo contador para las conexiones");
	}

	log_info(log, "CONEXIONES", "La cantidad de conexiones a crear es de %d",
			config.iCantMaxConex);
	/*DAN:*/
	conexiones = (struct poolConexiones *) malloc(
			sizeof(struct poolConexiones));
	conexiones->primero = NULL;
	conexiones->ultimo = NULL;

	struct nipc_protocol handshakeResponse;

	for (i = 0; i < config.iCantMaxConex; i++) {

		struct conexion * conexionParaAgregarAlPool =
				(struct conexion *) malloc(sizeof(struct conexion));

		//Se generan i cantidad de conexiones, siendo I el número agregado en el archivo de configuración.

		int32_t socketNuevo = prepararSocketInet(PROCESO);

		if (conectar(socketNuevo, config.sIPConex, config.iPuertoConex) == 1) {
			//Salió bien!
			NIPC_enviar(socketNuevo, '0', 512,"Handshake", 0);


			NIPC_recibir(&socketNuevo, &handshakeResponse);



			conexionParaAgregarAlPool->numeroDescriptor = socketNuevo;
			sem_init(&conexionParaAgregarAlPool->disponible, 0, 1);
//						pthread_mutex_init(, NULL);
						conexionParaAgregarAlPool->estaDisponible=1;
						conexionParaAgregarAlPool->siguiente = NULL;


			if (conexiones->primero == NULL) {
				//Es el primer nodo, por lo que conexiones->primero tiene que tener el valor de la conexion
				conexiones->primero = conexionParaAgregarAlPool;
				conexiones->ultimo = conexionParaAgregarAlPool;

			} else {

				//si no es el primero, pongo la dirección de memoria en la propiedad "siguiente" del nodo anterior,
				//y le asigno a anterior mi nuevo nodo
				conexionParaAgregarAlPool->siguiente = NULL;
				conexiones->ultimo->siguiente = conexionParaAgregarAlPool;
				conexiones->ultimo = conexionParaAgregarAlPool;

			}

		} else {
			log_error(log, "CONEXIONES", "Error en la creacion de las conexiones");
			return -1;
		}

//		free(conexionParaAgregarAlPool);
	}


//	free(anterior);

	return conexiones; // DAN: return &conexiones;
}

int32_t obtenerConexion() {

	/*
	 * Pasos a seguir
	 * 1) disminuir la cantidad del semáforo contador
	 * 2) Recorrer la cola de las conexiones hasta encontrar una libre (si pude entrar es porque hay alguna libre)
	 * 3) bloquear el mutex de la estructura de la conexión libre
	 * 4) Devolver la conexión
	 */

	struct conexion * siguiente = (struct conexion *) malloc(
			sizeof(struct conexion));

	siguiente = conexiones->primero;

	sem_wait(&conexionesTotales);
	uint32_t valueSem;
	while(siguiente){


		sem_getvalue(&(siguiente->disponible), &valueSem);

		printf("MUTEX: %d\n", valueSem);


		if (valueSem == 0) {

		 siguiente =siguiente->siguiente;

		}
		else{sem_wait(&(siguiente->disponible));
		return siguiente->numeroDescriptor;}
	}


	return -1;

}

int32_t liberarConexion(int32_t conexionALiberar) {
	/*
	 * Pasos a seguir
	 * 1) Recorrer la cola de conexiones preguntando por el número de descriptor
	 * 2) Una vez encontrado, liberar su mutex
	 * 3) */

	struct conexion * siguiente = (struct conexion *) malloc(
			sizeof(struct conexion));

	siguiente = conexiones->primero;

	while(siguiente){
		if (siguiente->numeroDescriptor == conexionALiberar) {

			sem_post(&siguiente->disponible);
//			siguiente->estaDisponible=1;
			sem_post(&conexionesTotales);
			return 1;

		}
		siguiente=siguiente->siguiente;

	}

	log_error(log, "CONEXIONES", "Error en el liberarConexion");

	return 0;
}
